﻿using Microsoft.VisualStudio.Modeling;
using System.Collections.Generic;
using System.Linq;

namespace Project.Co_DataTransformationPrototype
{
    partial class NamedElement
    {
        partial class NamePropertyHandler
        {
            protected override void OnValueChanged(NamedElement element, string oldValue, string newValue)
            {
                base.OnValueChanged(element, oldValue, newValue);
                Store store = element.Store;
                Entity sourceEntity = element as Entity;
                EntityAttribute sourceAttribute = element as EntityAttribute;

                // Let the transaction manager handle undo's.
                // - Ignore if model has just been opened, or element has just been created
                if (store.InUndoRedoOrRollback || store.InSerializationTransaction || string.IsNullOrEmpty(oldValue)) 
                    return;

                if (sourceEntity != null)
                {
                    // Propagate entity name change to its dependancies (FK constraint references)
                    updateFKConstraintsForEntity(sourceEntity, oldValue);
                }
                else if (sourceAttribute != null)
                {
                    // Propagate attribute name change to its dependencies (PK & FK constraints)
                    updateAttributeConstraints(sourceAttribute, oldValue);
                }
            }

            private void updateFKConstraintsForEntity(Entity sourceEntity, string oldEntityName)
            {
                Entity foreignReference;

                // Fix inward fk-reference
                foreach (Entity ent in sourceEntity.Targets)
                {
                    foreach (EntityAttribute attribute in ent.EntityAttributes.FindAll(a => a.isForeignKey == true))
                    {
                        // Drop FK constraint referencing the old entity name
                        Operators.Define(ent.Store).UpdateAttributeProperty(EntityAttribute.isForeignKeyDomainPropertyId, attribute, false, sourceEntity);
                        // Recreate FK contraint which has the correct entity name as its reference
                        Operators.Define(ent.Store).UpdateAttributeProperty(EntityAttribute.isForeignKeyDomainPropertyId, attribute, true, sourceEntity);
                    }
                }

                // Fix outward fk-reference
                foreach (EntityAttribute attribute in sourceEntity.EntityAttributes.FindAll(a => a.isForeignKey == true))
                {
                    foreignReference = attribute.Store.ElementDirectory.FindElement(attribute.ReferencedEntityID) as Entity;
                    // Drop FK constraint with the old entity-name in its name
                    Operators.Define(sourceEntity.Store).UpdateAttributeProperty(EntityAttribute.isForeignKeyDomainPropertyId, attribute, false, foreignReference, oldEntityName);
                    // Recreate same FK contraint using the correct entity-name
                    Operators.Define(sourceEntity.Store).UpdateAttributeProperty(EntityAttribute.isForeignKeyDomainPropertyId, attribute, true, foreignReference);
                }
            }

            private void updateAttributeConstraints(EntityAttribute sourceAttribute, string oldAttributeName)
            {
                Entity foreignReference;

                // Determine if it's a PK attribute
                if (sourceAttribute.isPrimaryKey)
                {
                    // Drop PK constraint which referenced the old attribute name
                    Operators.Define(sourceAttribute.Store).UpdateAttributeProperty(EntityAttribute.isPrimaryKeyDomainPropertyId, sourceAttribute, false, null, null, oldAttributeName);
                    // Recreate PK constraint dependent on proper attribute name (proper = column-name that exists)
                    Operators.Define(sourceAttribute.Store).UpdateAttributeProperty(EntityAttribute.isPrimaryKeyDomainPropertyId, sourceAttribute, true);
                }
                else if (sourceAttribute.isForeignKey)
                {
                    foreignReference = sourceAttribute.Store.ElementDirectory.FindElement(sourceAttribute.ReferencedEntityID) as Entity;
                    // Drop FK constraint with the old entity-name in its name
                    Operators.Define(sourceAttribute.Store).UpdateAttributeProperty(EntityAttribute.isForeignKeyDomainPropertyId, sourceAttribute, false, foreignReference, null, oldAttributeName);
                    // Recreate same FK contraint using the correct entity-name
                    Operators.Define(sourceAttribute.Store).UpdateAttributeProperty(EntityAttribute.isForeignKeyDomainPropertyId, sourceAttribute, true, foreignReference);
                }
            }

        }
    }
}
